home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Languages
/
PowerMacOberon 1.2
/
Dialogs
/
Dialogs.Mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1995-06-30
|
27KB
|
706 lines
Syntax10.Scn.Fnt
Syntax10i.Scn.Fnt
StampElems
Alloc
21 Apr 95
Syntax10b.Scn.Fnt
MODULE Dialogs;
(** extended version Markus Knasm
ller 25.May.94 -
IMPORT Display, Files, Modules, Oberon, TextFrames, TextPrinter, Texts, Types, Viewers;
CONST
ok* = 0; objectIsAlreadyInPanel* = 1; nameExists* = 2; objectNotFound* = 3;
wrongInput* = 4; noPanelSelected* = 5; objectWouldOverlap* = 6; tooManyObjectsSelected* = 7;
maxItems = 64;
TYPE
Object* = POINTER TO ObjectDesc;
Panel* = POINTER TO PanelDesc;
ObjectDesc* = RECORD
next: Object;
x, y, w, h: LONGINT;
name-: ARRAY 16 OF CHAR; (** a panel wide unique name *)
cmd-: ARRAY 32 OF CHAR; (** a command to be executed when the obj is changed *)
par-: ARRAY 32 OF CHAR;
(** the invoked commands can assume that Oberon.par.text contains the contest of these text items *)
selected-: BOOLEAN; (** TRUE if the object is selected *)
overlapping-: BOOLEAN; (** TRUE if the object may overlap others *)
panel-: Panel; (** panel containing the object *)
visible: BOOLEAN; (* TRUE if the object is visible *)
END;
PanelDesc* = RECORD
cmd-: ARRAY 64 OF CHAR; (** cmd which initialies the dialog *)
contents: Object;
END;
NotifyMsg* = RECORD(Display.FrameMsg)
id*: INTEGER; (** 0 = restore, 1 = hide, 2 = markMenu, 3 = restore all *)
obj*: Object; (** defined if id = 0 or id = 1 *)
p*: Panel; (** defined if id = 2 or id = 3 *)
END;
dUnit*, pUnit*: LONGINT; (** for device independent coordinates *)
res*: INTEGER; (** result code from last operation *)
Edit*: PROCEDURE (obj: Object);
Update*: PROCEDURE (obj: Object; p: Panel);
cmdPanel*: Panel; (** panel from which the last command was called *)
editPanel*: Panel; (** panel for editing the properties of an object *)
editObject*: Object; (** object which could be edited by editPanel *)
deInit*: Panel; (** panel representing DEInit.Dlg *)
lastin*: Object; (** most recently inserted object *)
w0: Texts.Writer;
PROCEDURE^ (p: Panel) MarkMenu*;
PROCEDURE^ (p: Panel) NamedObject* (name: ARRAY OF CHAR): Object;
PROCEDURE^ (p: Panel) GetObjects* (x, y, w, h: INTEGER; VAR obArray: ARRAY OF Object; VAR nofelems: INTEGER);
PROCEDURE^ (p: Panel) RestoreOverlapped (x, y, w, h: INTEGER; o: Object);
PROCEDURE^ (p: Panel) RemoveSelections*;
PROCEDURE (o: Object) Draw* (x, y: INTEGER; f: Display.Frame);
(** abstract: displays the object at (x, y) in frame f *)
END Draw ;
PROCEDURE (o: Object) Copy* (VAR dup: Object);
(** allocates dup and makes a deep copy of o. For calling this methode dup should be equal NIL *)
BEGIN
IF dup = NIL THEN NEW (dup) END;
dup.x := o.x; dup.y := o.y; dup.w := o.w; dup.h := o.h; dup.name := o.name; dup.next := NIL;
dup.cmd := o.cmd; dup.par := o.par; dup.selected := FALSE; dup.overlapping := o.overlapping; dup.panel := NIL;
END Copy;
PROCEDURE (o: Object) Print* (x, y: INTEGER);
(** abstract: prints the object at printer coordinates (x, y) *)
END Print;
PROCEDURE (o: Object) Handle* (f: Display.Frame; VAR msg: Display.FrameMsg);
(** abstract: handles messages which were sent to frame f *)
END Handle;
PROCEDURE (o: Object) Edit*;
(** opens a dialog for editing the properties of the object *)
BEGIN IF Edit # NIL THEN Edit (o) END
END Edit;
PROCEDURE (o: Object) Update* (p: Panel);
(** sets the properties of the object to the values defined in the dialog p opened with Edit *)
BEGIN IF Update # NIL THEN Update (o, p) END
END Update;
PROCEDURE (o: Object) Init*;
(** initialies the object, should be called after allocating the object with NEW *)
BEGIN o.selected := FALSE; o.panel := NIL; o.cmd[0] := 0X; o.par[0] := 0X; o.visible := TRUE;
END Init;
PROCEDURE (o: Object) GetDim* (VAR x, y, w, h: INTEGER);
(** Gets x, y, width and height of object o for drawing *)
BEGIN
x := SHORT (o.x DIV dUnit); y := SHORT (o.y DIV dUnit);
w := SHORT (o.w DIV dUnit); h := SHORT (o.h DIV dUnit);
END GetDim;
PROCEDURE (o: Object) GetPDim* (VAR x, y, w, h: INTEGER);
(** Gets x, y, width and height of object o for printing *)
BEGIN
x := SHORT (o.x DIV pUnit); y := SHORT (o.y DIV pUnit);
w := SHORT (o.w DIV pUnit); h := SHORT (o.h DIV pUnit);
END GetPDim;
PROCEDURE (o: Object) Load* (VAR r: Files.Rider);
(** reads the object from rider r *)
VAR name1: ARRAY 64 OF CHAR; cmd1, par1: ARRAY 64 OF CHAR;
BEGIN
o.Init; Files.ReadString (r, name1); COPY (name1, o.name);
Files.ReadString (r, cmd1); COPY (cmd1, o.cmd);
Files.ReadString (r, par1); COPY (par1, o.par);
Files.ReadLInt (r, o.x); Files.ReadLInt (r, o.y); Files.ReadLInt (r, o.w);
Files.ReadLInt (r, o.h); Files.ReadBool (r, o.overlapping)
END Load;
PROCEDURE (o: Object) Store* (VAR r: Files.Rider);
(** writes the object to rider r *)
BEGIN
Files.WriteString (r, o.name); Files.WriteString (r, o.cmd); Files.WriteString (r, o.par); Files.WriteLInt (r, o.x);
Files.WriteLInt (r, o.y); Files.WriteLInt (r, o.w); Files.WriteLInt (r, o.h); Files.WriteBool (r, o.overlapping)
END Store;
PROCEDURE (o: Object) CallCmd* (f: Display.Frame; v: Viewers.Viewer; t: Texts.Text);
(** invokes the command obj.cmd *)
VAR callres: INTEGER;
BEGIN
IF o.cmd[0] # 0X THEN
Oberon.Par.frame := f; Oberon.Par.vwr := v; Oberon.Par.text := t; Oberon.Par.pos := 0;
cmdPanel := o.panel; Oberon.Call (o.cmd, Oberon.Par, FALSE, callres)
END
END CallCmd;
PROCEDURE (o: Object) SetCmd* (cmd: ARRAY OF CHAR);
(** sets the command of the object to cmd *)
BEGIN
IF cmd # o.cmd THEN
COPY (cmd, o.cmd);
IF o.panel # NIL THEN o.panel.MarkMenu END
END
END SetCmd;
PROCEDURE (o: Object) SetPar* (par: ARRAY OF CHAR);
(** sets the command of the object to par *)
BEGIN
IF par # o.par THEN
COPY (par, o.par);
IF o.panel # NIL THEN o.panel.MarkMenu END
END
END SetPar;
PROCEDURE (o: Object) Restore*;
(** restores object o => redraws it *)
VAR msg: NotifyMsg;
BEGIN msg.id := 0; msg.obj := o; Viewers.Broadcast (msg); o.visible := TRUE
END Restore;
PROCEDURE (o: Object) SetName* (name: ARRAY OF CHAR);
(** sets the name of the object to name, unless in the panel containing o already exists such a name *)
BEGIN
IF (o.panel = NIL) OR (name[0] = 0X) OR (o.panel.NamedObject (name) = NIL) OR (o.panel.NamedObject (name) = o) THEN
IF o.name # name THEN
COPY (name, o.name); res := ok;
IF o.panel # NIL THEN
o.panel.MarkMenu; o.Restore;
END
END
ELSE res := nameExists
END
END SetName;
PROCEDURE (o: Object) Hide*;
(** removes object from screen, but not from panel *)
VAR msg: NotifyMsg; ox, oy, ow, oh, nofelems, i: INTEGER; obArray: ARRAY 50 OF Object;
BEGIN
IF o.panel = NIL THEN RETURN END;
msg.id := 1; msg.obj := o; Viewers.Broadcast (msg); o.visible := FALSE;
IF o.overlapping THEN
o.GetDim (ox, oy, ow, oh);
o.panel.RestoreOverlapped (ox, oy, ow, oh, o);
(*o.panel.GetObjects (ox, oy, ow, oh, obArray, nofelems); i := 0;
WHILE i < nofelems DO
IF obArray[i] # o THEN obArray[i].Restore END;
INC (i)
END *)
END
END Hide;
PROCEDURE (o: Object) Select* ();
(** selects o and displays it selected *)
VAR x, y, w, h: INTEGER;
BEGIN
IF ~ o.selected THEN
o.selected := TRUE; o.Hide;
o.Restore
END
END Select;
PROCEDURE (o: Object) UnSelect* ();
(** unselects o and displays it unselected *)
VAR x, y, w, h: INTEGER;
BEGIN
IF o.selected THEN
o.selected := FALSE; o.Hide; o.Restore;
END
END UnSelect;
PROCEDURE (o: Object) IsIn (x, y, w, h: INTEGER): BOOLEAN;
VAR x0, y0, w0, h0: LONGINT;
BEGIN
x0 := x * dUnit; y0 := y * dUnit; w0 := w * dUnit; h0 := h * dUnit;
IF ~ (y0 + h0 < o.y) THEN
IF (y0 + h0 >= o.y) & (y0 + h0 <= o.y + o.h) &
~ (((x0 < o.x) & (x0 + w0 < o.x)) OR (x0 > o.x + o.w)) THEN
RETURN TRUE
END;
IF (y0 + h0 > o.y + o.h) & (y0 <= o.y + o.h) &
~ (((x0 < o.x) & (x0 + w0 < o.x)) OR (x0 > o.x + o.w)) THEN
RETURN TRUE
END
END;
RETURN FALSE
END IsIn;
PROCEDURE (o: Object) IsOverlapped (x, y, w, h: INTEGER): BOOLEAN;
VAR x0, y0 , w0, h0: LONGINT;
BEGIN
x0 := x * dUnit; y0 := y * dUnit; w0 := w * dUnit; h0 := h * dUnit;
RETURN (o.x >= x0) & (o.y >= y0) & (o.x + o.w <= x0 + w0) & (o.y + o.h <= y0 + h0)
END IsOverlapped;
PROCEDURE (o: Object) IsOverlapping (p: Panel; x, y, w, h: LONGINT; sel: BOOLEAN): BOOLEAN;
(* Returns TRUE if o with new dimensions x, y, w, h would overlapping another object of panel p.
If sel then overlapping a selected object doesn`t matter. *)
VAR o1: Object; b: BOOLEAN; hx, hy, hw, hh: LONGINT;
BEGIN
IF o.overlapping THEN RETURN FALSE END;
o1 := p.contents;
WHILE o1 # NIL DO
IF (o1 # o) & ~ o1.overlapping & ~(o1.selected & sel) THEN
IF (o1.y < y + h) & (o1.y + o1.h > y) & (o1.x < x + w) & (o1.x + o1.w > x) THEN RETURN TRUE END
END;
o1 := o1.next
END;
RETURN FALSE
END IsOverlapping;
PROCEDURE (o: Object) SetDim* (x, y, w, h: INTEGER; cond: BOOLEAN);
(** Sets x, y, width and height of object o *)
VAR ox, oy, ow, oh: LONGINT; ax, ay, aw, ah: INTEGER;
BEGIN
o.GetDim (ax, ay, aw, ah);
ox := x * dUnit; oy := y * dUnit; ow := w * dUnit; oh := h * dUnit;
IF ow < dUnit THEN ow := dUnit END; IF oh < dUnit THEN oh := dUnit END;
IF o.panel = NIL THEN
o.x := ox; o.y := oy; o.w := ow; o.h := oh; res := ok
ELSIF ~ o.IsOverlapping (o.panel, ox, oy, ow, oh, cond) THEN
IF ~ o.selected THEN o.panel.RemoveSelections END;
o.Hide; o.x := ox; o.y := oy; o.w := ow; o.h := oh;
o.Restore; o.panel.MarkMenu;
o.panel.RestoreOverlapped (ax, ay, aw, ah, o); res := ok
ELSE
res := objectWouldOverlap
END;
END SetDim;
PROCEDURE (o: Object) OverlappingObject* (): Object;
(** returns the object overlapping this object *)
VAR o1, ret: Object; x, y, w, h, w1, h1: INTEGER;
BEGIN
IF o.panel = NIL THEN RETURN NIL END;
o1 := o.panel.contents; ret := NIL;
WHILE o1 # NIL DO
IF (o # o1) & (o1.overlapping) THEN
o1.GetDim (x, y, w, h);
IF o.IsIn (x, y, w, h) THEN
IF (ret = NIL) THEN
ret := o1
ELSE
ret.GetDim (x, y, w1, h1);
IF w1 * h1 > w * h THEN ret := o1 END
END;
END
END;
o1 := o1.next;
END;
RETURN ret
END OverlappingObject;
PROCEDURE (p: Panel) RestoreOverlapped (x, y, w, h: INTEGER; o: Object);
VAR o1: Object;
PROCEDURE Redraw;
BEGIN
IF o1.selected THEN
IF o1.visible THEN o1.Hide END;
o1.Restore
ELSE o1.Restore
END
END Redraw;
BEGIN
o1 := p.contents;
WHILE o1 # NIL DO
IF (o1 # o) & o1.overlapping & o1.visible & o1.IsIn (x, y, w, h) THEN Redraw END;
o1 := o1.next
END;
IF o.overlapping THEN
o1 := p.contents;
WHILE o1 # NIL DO
IF (o1 # o) & ~ o1.overlapping & o1.visible & o1.IsIn (x, y, w, h) THEN Redraw END;
o1 := o1.next
END
END
END RestoreOverlapped;
PROCEDURE (p: Panel) SetCmd* (cmd: ARRAY OF CHAR);
(** sets the command of the object to cmd *)
BEGIN
IF cmd # p.cmd THEN
COPY (cmd, p.cmd);
p.MarkMenu
END
END SetCmd;
PROCEDURE (p: Panel) NamedObject* (name: ARRAY OF CHAR): Object;
(** returns the object with name name *)
VAR o: Object;
BEGIN
IF name = "" THEN RETURN NIL END;
o := p.contents;
WHILE (o # NIL) & (o.name # name) DO o := o.next END;
RETURN o
END NamedObject;
PROCEDURE (p: Panel) Select* (x, y, w, h: INTEGER);
(** selects all objects in p which are lying under the box specified by x, y, w, h *)
VAR o: Object;
BEGIN
o := p.contents;
WHILE o # NIL DO
IF o.IsIn (x, y, w, h) THEN o.Select ELSE o.UnSelect END;
o := o.next
END
END Select;
PROCEDURE (p: Panel) GetObjects* (x, y, w, h: INTEGER; VAR obArray: ARRAY OF Object; VAR nofelems: INTEGER);
(** gets all objects in p which are lying unter the box specified by x, y, w, h *)
VAR o: Object;
BEGIN
nofelems := 0; o := p.contents;
WHILE (o # NIL) & (nofelems < LEN (obArray)) DO
IF o.IsIn (x, y, w, h) THEN obArray [nofelems] := o; INC (nofelems) END;
o := o.next;
END
END GetObjects;
PROCEDURE (p: Panel) MarkMenu*;
(** marks the menu of the frames which are displaying p *)
VAR msg: NotifyMsg;
BEGIN msg.id := 2; msg.p := p; Viewers.Broadcast (msg);
END MarkMenu;
PROCEDURE (p: Panel) Restore*;
(** restores the panel p => redraws it *)
VAR msg: NotifyMsg;
BEGIN msg.id := 3; msg.p := p; Viewers.Broadcast (msg)
END Restore;
PROCEDURE (p: Panel) Remove* (o: Object);
(** removes object o of panel p *)
VAR q, prev: Object;
BEGIN
q := p.contents;
WHILE (q # NIL) & (q # o) DO prev := q; q := q.next END;
IF q # NIL THEN
q.Hide;
IF q = p.contents THEN p.contents := q.next ELSE prev.next := q.next END;
q.next := NIL; res := ok; p.MarkMenu
ELSE
res := objectNotFound
END
END Remove;
PROCEDURE (p: Panel) RemoveObjects* (x, y, w, h: INTEGER);
(** deletes all objects in p which are within x, y, w, h *)
VAR o, next: Object;
BEGIN
o := p.contents;
WHILE o # NIL DO
next := o.next;
IF o.IsIn (x, y, w, h) THEN p.Remove (o) END;
o := next;
END
END RemoveObjects;
PROCEDURE (p: Panel) Enumerate* (handle: PROCEDURE (obj: Object; VAR done: BOOLEAN));
(** calls the procedure handle for every object of the panel *)
VAR obj: Object; done: BOOLEAN;
BEGIN
done := FALSE; obj := p.contents;
WHILE (obj # NIL) & ~ done DO handle (obj, done); obj := obj.next END
END Enumerate;
PROCEDURE (p:Panel) RemoveSelections* ();
(** Unselects all objects *)
VAR o: Object;
BEGIN
o := p.contents;
WHILE o # NIL DO o.UnSelect (); o := o.next END;
END RemoveSelections;
PROCEDURE (p: Panel) Insert* (o: Object; ov: BOOLEAN);
(** inserts object o in panel p *)
VAR i, x0, j: INTEGER; a, b: ARRAY 15 OF CHAR;
BEGIN
o.overlapping := ov;
IF ~ o.IsOverlapping(p, o.x, o.y, o.w, o.h, FALSE) THEN
IF p.NamedObject (o.name) = NIL THEN
o.panel := p; o.next := p.contents; p.contents := o;
o.Restore; o.panel.MarkMenu; lastin := o;
ELSE res := nameExists
END
ELSE res := objectWouldOverlap
END
END Insert;
PROCEDURE (p: Panel) Copy* (): Panel;
(** returns a deep copy of p *)
VAR copy: Panel; o, o1: Object;
BEGIN
NEW (copy); o := p.contents; copy.cmd := p.cmd;
WHILE o # NIL DO
o1 := NIL; o.Copy (o1); copy.Insert (o1, o.overlapping); o := o.next;
END;
RETURN copy
END Copy;
PROCEDURE (p: Panel) NofSelObjects* (): INTEGER;
(** returns the number of selected objects in p *)
VAR o: Object; count: INTEGER;
BEGIN
o := p.contents; count := 0;
WHILE o # NIL DO
IF o.selected THEN INC (count) END;
o := o.next
END;
RETURN (count)
END NofSelObjects;
PROCEDURE (p: Panel) ThisObject* (x, y: INTEGER): Object;
(** returns the object including the coordinates x and y; first it tries to get a not overlapping object *)
VAR o1, o: Object; x0, y0: LONGINT;
BEGIN
o := p.contents; o1:= NIL;
x0 := x * dUnit; y0 := y * dUnit;
WHILE o # NIL DO
IF (x0 >= o.x) & (x0 < o.x + o.w) & (y0 >= o.y) & (y0 < o.y + o.h) THEN
IF (o1 = NIL) OR ~ o.overlapping THEN o1 := o END
END;
o := o.next
END;
RETURN o1
END ThisObject;
PROCEDURE (p: Panel) Draw* (x, y: INTEGER; f: Display.Frame);
(** draws the panel at (x, y) in frame f *)
VAR o: Object; ox, oy, ow, oh: INTEGER;
BEGIN
o := p.contents;
WHILE o # NIL DO
IF o.overlapping THEN o.GetDim (ox, oy, ow, oh); o.Draw (x + ox, y + oy , f) END;
o := o.next
END;
o := p.contents;
WHILE o # NIL DO
IF ~ o.overlapping THEN o.GetDim (ox, oy, ow, oh); o.Draw (x + ox, y + oy , f) END;
o := o.next
END
END Draw;
PROCEDURE (p: Panel) Print* (x, y: INTEGER);
(** prints the panel at printer coordinates (x, y) *)
VAR o: Object; ox, oy, ow, oh: INTEGER;
BEGIN
o := p.contents;
WHILE o # NIL DO
o.GetPDim (ox, oy, ow, oh); o.Print (x + ox, y + oy); o := o.next
END
END Print;
PROCEDURE (p: Panel) Load* (VAR r: Files.Rider);
(** reads the panel from rider r *)
VAR cnt, end1, end2, h: INTEGER; o, prev: Object; module: Modules.ModuleName; name: ARRAY 32 OF CHAR;
tab1: ARRAY maxItems OF Modules.ModuleName; tab2: ARRAY maxItems OF ARRAY 32 OF CHAR;
pos: LONGINT;
BEGIN
p.contents := NIL; prev := NIL; Files.ReadInt(r, cnt); COPY ("", p.cmd); end1 := 0; end2 := 0;
WHILE cnt # 0 DO DEC (cnt);
pos := Files.Pos (r); Files.ReadInt (r, h);
IF h < end1 THEN module := tab1[h]
ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, module); tab1[end1] := module; INC (end1)
END;
pos := Files.Pos (r); Files.ReadInt (r, h);
IF h < end2 THEN COPY (tab2[h], name)
ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, name); COPY (name, tab2[end2]); INC (end2)
END;
Types.NewObj (o, Types.This (Modules.ThisMod (module), name)); ASSERT (o # NIL);
o.Load (r); o.panel := p;
IF prev # NIL THEN prev.next := o ELSE p.contents := o END;
prev := o
END;
Files.ReadString (r, p.cmd);
p.Restore ()
END Load;
PROCEDURE (p: Panel) Store* (VAR r: Files.Rider);
(** stores the panel from rider r *)
VAR cnt, end1, end2, i: INTEGER; o: Object; type: Types.Type; cond: BOOLEAN;
tab1, tab2: ARRAY maxItems OF ARRAY 32 OF CHAR;
BEGIN
o := p.contents; cnt := 0; end1 := 0; end2 := 0;
WHILE o # NIL DO INC (cnt); o := o.next END;
Files.WriteInt (r, cnt); o := p.contents;
WHILE o # NIL DO
type := Types.TypeOf (o); cond := FALSE;
FOR i := 0 TO end1 -1 DO
IF tab1[i] = type.module.name THEN Files.WriteInt (r, i); cond := TRUE END;
END;
IF ~cond THEN Files.WriteString (r, type.module.name); COPY (type.module.name, tab1[end1]); INC (end1) END;
cond := FALSE;
FOR i := 0 TO end2 -1 DO
IF tab2[i] = type.name THEN Files.WriteInt (r, i); cond := TRUE END;
END;
IF ~cond THEN Files.WriteString (r, type.name); COPY (type.name, tab2[end2]); INC (end2) END;
o.Store (r); o := o.next
END;
Files.WriteString (r, p.cmd)
END Store;
PROCEDURE (p: Panel) Contains* (o: Object): BOOLEAN;
(** returns TRUE if the panel contains o *)
VAR o1: Object;
BEGIN
o1 := p.contents;
WHILE o1 # NIL DO
IF o1 = o THEN RETURN TRUE END;
o1 := o1.next
END;
RETURN FALSE
END Contains;
PROCEDURE (p: Panel) MoveSelected* (dx, dy: INTEGER);
(** moves all selected objects around dx and dy *)
VAR
o: Object; ov: BOOLEAN; msg: NotifyMsg;
ox, oy, ow, oh, i, nofelems: INTEGER; dx0, dy0: LONGINT;
obArray: ARRAY 50 OF Object;
BEGIN
IF p.NofSelObjects () = 0 THEN res := ok; RETURN END;
o := p.contents; ov := FALSE;
dx0 := dx * dUnit; dy0 := dy * dUnit;
WHILE (o # NIL) & (~ ov) DO
IF o.selected THEN ov := o.IsOverlapping (p, o.x + dx0, o.y + dy0, o.w, o.h, TRUE) END;
o := o.next
END;
o := p.contents;
IF ~ ov THEN
WHILE o # NIL DO
IF o.selected THEN
msg.id := 1; msg.obj := o; Viewers.Broadcast (msg);
o.GetDim (ox, oy, ow, oh); p.GetObjects (ox, oy, ow, oh, obArray, nofelems); i := 0;
WHILE i < nofelems DO
IF (~ obArray[i].selected) THEN obArray[i].Restore END;
INC (i)
END
END;
o := o.next
END;
o := p.contents;
WHILE o # NIL DO
IF o.selected THEN o.x := o.x + dx0; o.y := o.y + dy0 END;
o := o.next
END;
o := p.contents;
WHILE o # NIL DO
IF o.selected & o.overlapping THEN o.Restore END;
o := o.next
END;
o := p.contents;
WHILE o # NIL DO
IF o.selected & ~ o.overlapping THEN o.Restore END;
o := o.next
END;
res := ok; p.MarkMenu
ELSE
res := objectWouldOverlap
END
END MoveSelected;
PROCEDURE (p: Panel) ChangeDistance (dir: CHAR);
VAR sort: ARRAY 50 OF Object; n, i: INTEGER; o: Object; d: LONGINT;
PROCEDURE Greater (o1, o2: Object): BOOLEAN;
BEGIN
IF (dir = "R") OR (dir = "L") THEN RETURN o1.x > o2.x ELSE RETURN o1.y > o2.y END
END Greater;
BEGIN
(* ---- sort objects *)
o := p.contents; n := 0;
WHILE o # NIL DO
IF o.selected THEN
i := n - 1;
WHILE (i >= 0) & Greater (sort [i], o) DO
sort [i + 1] := sort [i]; DEC (i)
END;
sort [i + 1] := o; INC (n)
END;
o := o.next
END;
(* ---- calculate distance *)
d := 0;
IF (dir = "R") OR (dir = "L") THEN
FOR i := 0 TO n - 2 DO d := d + sort[i].x - sort[i + 1].x - sort[i + 1].w END
ELSE
FOR i := 0 TO n - 2 DO d := d + sort[i].y - sort[i + 1].y - sort[i + 1].h END
END;
d := d DIV (n - 1);
(* ---- change distance *)
IF (dir = "R") OR (dir = "L") THEN
FOR i := 0 TO n - 2 DO sort[i + 1].x := sort[i].x - sort[i + 1].w - d END
ELSIF (dir = "U") OR (dir = "D") THEN
FOR i := 0 TO n - 2 DO sort[i + 1].y := sort[i].y - sort[i + 1].h - d END
END
END ChangeDistance;
PROCEDURE (p: Panel) AlignTest (dir: CHAR; x: LONGINT): BOOLEAN;
(* returns TRUE if Align with parameters dir and x is not possible *)
VAR p2: Panel; o: Object;
BEGIN
p2 := p.Copy (); o := p2.contents;
WHILE o # NIL DO
IF o.selected THEN
IF dir = "R" THEN o.x := x - o.w
ELSIF dir = "L" THEN o.x := x
ELSIF dir = "U" THEN o.y := x - o.h
ELSIF dir = "D" THEN o.y := x
END;
END;
o := o.next
END;
o := p2.contents;
WHILE o # NIL DO
IF o.IsOverlapping (p2, o.x, o.y, o.w, o.h, FALSE) THEN RETURN TRUE END;
o := o.next
END;
RETURN FALSE
END AlignTest;
PROCEDURE (p: Panel) RegulateDistanceTest (dir: CHAR): BOOLEAN;
(* returns TRUE if RegulateDistance with parameters dir and x is not possible *)
VAR p2: Panel; o: Object;
BEGIN
p2 := p.Copy (); p2.ChangeDistance (dir); o := p2.contents;
WHILE o # NIL DO
IF o.IsOverlapping (p2, o.x, o.y, o.w, o.h, FALSE) THEN RETURN TRUE END;
o := o.next
END;
RETURN FALSE
END RegulateDistanceTest;
PROCEDURE (p: Panel) AlignSelected* (dir: CHAR);
(** aligns the selected objects according to dir (Right, Left, Up or Down) *)
VAR o: Object; x: LONGINT;
PROCEDURE Max;
BEGIN
IF dir = "R" THEN IF o.x + o.w > x THEN x := o.x + o.w END
ELSIF dir = "L" THEN IF o.x < x THEN x := o.x END
ELSIF dir = "U" THEN IF o.y + o.h > x THEN x := o.y + o.h END
ELSIF dir = "D" THEN IF o.y < x THEN x := o.y END
END
END Max;
BEGIN
IF (dir # "R") & (dir # "L") & (dir # "U") & (dir # "D") THEN res := wrongInput; RETURN END;
IF p.NofSelObjects() = 0 THEN res:= ok; RETURN END;
o := p.contents;
IF (dir = "R") OR (dir = "D") THEN
x := 0
ELSIF (dir = "L") THEN
x := MAX (LONGINT)
ELSE
x := MIN (LONGINT);
END;
WHILE o # NIL DO
IF o.selected THEN Max END;
o := o.next
END;
IF ~ p.AlignTest (dir, x) THEN
o := p.contents;
WHILE o# NIL DO
IF o.selected THEN
IF dir = "R" THEN o.x := x - o.w
ELSIF dir = "L" THEN o.x := x
ELSIF dir = "U" THEN o.y := x - o.h
ELSIF dir = "D" THEN o.y := x
END
END;
o := o.next;
END;
p.Restore; res := ok; p.MarkMenu
ELSE
res := objectWouldOverlap
END
END AlignSelected;
PROCEDURE (p: Panel) RegulateDistance* (dir: CHAR);
(** aligns the selected objects along the direction dir such that they are equidistant *)
BEGIN
IF (dir # "R") & (dir # "L") & (dir # "U") & (dir # "D") THEN res := wrongInput; RETURN END;
IF p.NofSelObjects () > 50 THEN res := tooManyObjectsSelected; RETURN END;
IF p.NofSelObjects () < 3 THEN res := ok; RETURN END;
IF ~ p.RegulateDistanceTest (dir) THEN
p.ChangeDistance (dir);
p.Restore (); res := ok; p.MarkMenu
ELSE
res := objectWouldOverlap
END
END RegulateDistance;
PROCEDURE (p: Panel) Broadcast* (f: Display.Frame; VAR m: Display.FrameMsg);
(** sends the message m to all objects in the panel p which is displayed in frame f *)
VAR o, o1: Object;
BEGIN
o := p.contents;
WHILE o # NIL DO
o.Handle (f, m); o := o.next;
END
END Broadcast;
PROCEDURE Error* (name: ARRAY OF CHAR);
(** writes an error message to the log viewer *)
BEGIN
Texts.WriteString (w0, name);
IF res = objectIsAlreadyInPanel THEN Texts.WriteString (w0, " Error 1: Object is already in Panel")
ELSIF res = nameExists THEN Texts.WriteString (w0, " Error 2: Name exists")
ELSIF res = objectNotFound THEN Texts.WriteString (w0, " Error 3: Object not found")
ELSIF res = wrongInput THEN Texts.WriteString (w0, " Error 4: Wrong input")
ELSIF res = noPanelSelected THEN Texts.WriteString (w0, "Error 5: No panel selected")
ELSIF res = objectWouldOverlap THEN Texts.WriteString
(w0, " Error 6: Object would overlap another object")
ELSIF res = tooManyObjectsSelected THEN Texts.WriteString
(w0, " Error 7: Too many objects selected")
ELSE Texts.WriteInt (w0, res, 5)
END;
Texts.WriteLn (w0);
Texts.Append (Oberon.Log, w0.buf)
END Error;
BEGIN
dUnit := TextFrames.Unit; pUnit := TextPrinter.Unit; Edit := NIL; Update := NIL;
res := ok; editPanel := NIL; cmdPanel := NIL; editObject := NIL; lastin := NIL;
Texts.OpenWriter (w0);
END Dialogs.